#pragma once

using namespace System;
using namespace System::IO;
using namespace NUnit::Framework;
using namespace LatoolNet;

namespace LatoolNetTest {

	[TestFixture]
	public ref class ComplexMatrixTest {
	public:

		[Test]
		void TestSaveLoad() {

			int rownum = 6;
			int colnum = 6;
			ComplexMatrix ^ origmat = gcnew ComplexMatrix(rownum, colnum);

			Random^ randgen = gcnew Random();

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randgen->NextDouble() * 10;
					double imag = randgen->NextDouble() * 10;
					origmat[i, j] = Complex(real, imag);
				}
			}

			MatrixFormatter^ format = gcnew MatrixFormatter();
			format->NumberOfDigit = 0;
			ComplexMatrix::Save(origmat, format, "./savedat.txt");

			ComplexMatrix ^ loadmat = ComplexMatrix::Load("./savedat.txt");

			Assert::AreEqual(origmat->RowNum, loadmat->RowNum, "Test: Save/Load");
			Assert::AreEqual(origmat->ColNum, loadmat->ColNum, "Test: Save/Load");

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(origmat[i, j].Real, loadmat[i, j].Real, 1e-10, "Test: Save/Load");
					Assert::AreEqual(origmat[i, j].Imag, loadmat[i, j].Imag, 1e-10, "Test: Save/Load");

				}
			}

			//File::Delete("./savedat.txt");
		};

		[Test]
		void TestRowVector() {

			ComplexMatrix^ expected = gcnew ComplexMatrix(4, 4);
			Random^ rgen = gcnew Random();

			expected[0, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[1, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[2, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[3, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			ComplexMatrix^ actual = gcnew ComplexMatrix(4, 4);
			for (int r = 0; r < 4; r++) {
				ComplexMatrix^ rowVector = ComplexMatrix::RowVector(expected, r);
				for (int c = 0; c < 4; c++) {
					actual[r, c] = rowVector[0, c];
				}
			}

			ComplexMatrix^ verify = expected->Inv() * actual;

			for (int i = 0; i < 4; i++) {
				for (int j = 0; j < 4; j++) {
					if (i == j) {
						Assert::AreEqual(1.0, verify[i, j].Real, 1e-10, "Test: RowVector value");
						Assert::AreEqual(0.0, verify[i, j].Imag, 1e-10, "Test: RowVector value");

					} else {
						Assert::AreEqual(0.0, verify[i, j].Real, 1e-10, "Test: RowVector value");
						Assert::AreEqual(0.0, verify[i, j].Imag, 1e-10, "Test: RowVector value");
					}
				}
			}

		};

		[Test]
		void TestColVector() {

			ComplexMatrix^ expected = gcnew ComplexMatrix(4, 4);
			Random^ rgen = gcnew Random();

			expected[0, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[0, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[1, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[1, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[2, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[2, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			expected[3, 0] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 1] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 2] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));
			expected[3, 3] = Complex(rgen->Next(-10, 10), rgen->Next(-10, 10));

			ComplexMatrix^ actual = gcnew ComplexMatrix(4, 4);
			for (int c = 0; c < 4; c++) {
				ComplexMatrix^ colVector = ComplexMatrix::ColVector(expected, c);
				for (int r = 0; r < 4; r++) {
					actual[r, c] = colVector[r, 0];
				}
			}

			ComplexMatrix^ verify = expected->Inv() * actual;

			for (int i = 0; i < 4; i++) {
				for (int j = 0; j < 4; j++) {
					if (i == j) {
						Assert::AreEqual(1.0, verify[i, j].Real, 1e-10, "Test: ColVector value");
						Assert::AreEqual(0.0, verify[i, j].Imag, 1e-10, "Test: ColVector value");
					} else {
						Assert::AreEqual(0.0, verify[i, j].Real, 1e-10, "Test: ColVector value");
						Assert::AreEqual(0.0, verify[i, j].Imag, 1e-10, "Test: ColVector value");
					}
				}
			}
		};
	};
}